-
Notifications
You must be signed in to change notification settings - Fork 28
Added RobustHTTPClient as a beta API #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| * THE SOFTWARE. | ||
| */ | ||
|
|
||
| package io.jenkins.plugins.httpclient; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Package name does differ from artifactId. I would propose apache.httpcomponents.client.api or so.
OTOH the code does not use the library on its own. So more reviews may be required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That package name is pretty awkward, and also gives the false impression that this is Apache code.
Using the artifactId ~ shortName, in some modified form, as a final package component is indeed typical. This particular artifactId is quite unwieldy though. Also I am not sure there is a solid convention for “miscellaneous source packages added to a library wrapper”, which is not really the same as “main source package of a regular plugin”.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume Oleg meant io.jenkins.plugins.apache.httpcomponents.client.api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally - is converted to _ or camel casing when constructing a package component from an artifactId, so something like io.jenkins.plugins.apache_httpcomponents_client_4_api. Pretty ugly.
| public void connect(String whatConcise, String whatVerbose, ConnectionCreator connectionCreator, ConnectionUser connectionUser, TaskListener listener) throws IOException, InterruptedException { | ||
| AtomicInteger responseCode = new AtomicInteger(); | ||
| int attempt = 1; | ||
| while (true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a little complex to follow, there are too many alternatives in the same method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW the original version, which depended on the guava-retrying library that is supposed to wrap this logic in a pretty higher-level API, was just as long and (I think) harder to follow.
| try { | ||
| executors.submit(() -> { | ||
| responseCode.set(0); | ||
| try (CloseableHttpClient client = HttpClients.createSystem()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not join the two try?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They have different scopes.
| try (CloseableHttpClient client = HttpClients.createSystem()) { | ||
| try (CloseableHttpResponse response = connectionCreator.connect(client)) { | ||
| StatusLine statusLine = response.getStatusLine(); | ||
| responseCode.set(statusLine != null ? statusLine.getStatusCode() : 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe make the ? in the declaration is more clear
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing, I read response.getStatusLine() instead statusLine.getStatusCode()
| try (CloseableHttpResponse response = connectionCreator.connect(client)) { | ||
| StatusLine statusLine = response.getStatusLine(); | ||
| responseCode.set(statusLine != null ? statusLine.getStatusCode() : 0); | ||
| if (responseCode.get() < 200 || responseCode.get() >= 300) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if there is a redirection 301/302?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Treated as a failure currently. The existing use cases do not require following redirects. It would be possible to handle I think if there were some use case.
| Header contentEncoding = entity.getContentEncoding(); | ||
| diag = IOUtils.toString(err, contentEncoding != null ? contentEncoding.getValue() : null); | ||
| } | ||
| } else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe you can initialized diag to null and remove the else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could, I just have a mild preference for effectively final variables.
| } else { | ||
| diag = null; | ||
| } | ||
| throw new AbortException(String.format("Failed to %s, response: %d %s, body: %s", whatVerbose, responseCode.get(), statusLine != null ? statusLine.getReasonPhrase() : "?", diag)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you make the ? in the declaration of statusLine you have not repeat the code here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still not sure I am following. You mean, make statusLine nonnull by creating a fake object as a fallback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forget I mixed method names
| } | ||
| return null; // success | ||
| }).get(timeout, TimeUnit.SECONDS); | ||
| } catch (TimeoutException x) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can move it a level up and move the Exception wrapper to a method, this makes the code simpler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought about doing that but did not see a way to do so without making things much more complicated.
| * @return the same, but with any query string concealed | ||
| */ | ||
| public static String sanitize(URL url) { | ||
| return url.toString().replaceFirst("[?].+$", "?…"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure, but Could be interesting to remove the stuff between @ and //? I mean, if we have the URL http://U:P@HOST?QUERY we replace it with http://U:P@HOST?..., it is possible to make the same with the user and password and transform the URL to http://..@HOST?...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
passwords should be removed, user would be ok
also, should it be three chars ... or one unicode char …? I think the former
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL.userInfo is generally opaque, not necessarily user:pass. It could be masked if needed. Currently there is no use case for doing so, as (semi-)secrets are passed in the query string.
carlossg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO if this is exposed it lacks docs on how to use it and an example
We should move some of the mock tests from downstream to here
| * @return the same, but with any query string concealed | ||
| */ | ||
| public static String sanitize(URL url) { | ||
| return url.toString().replaceFirst("[?].+$", "?…"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
passwords should be removed, user would be ok
also, should it be three chars ... or one unicode char …? I think the former
Well, there is Javadoc…
The upload and download methods are examples of using the base method.
Not possible I think. |
|
@carlossg do you consider this OK to merge? (I cannot request you as a reviewer.) I think would be up to @oleg-nenashev or @dwnusbaum to actually do so. |
| public static String sanitize(URL url) { | ||
| try { | ||
| URI orig = url.toURI(); | ||
| return new URI(orig.getScheme(), orig.getUserInfo() != null ? "…" : null, orig.getHost(), orig.getPort(), orig.getPath(), orig.getQuery() != null ? "…" : null, orig.getFragment()).toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked before, is … intended or should be ... ? will unicode behave correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either should be fine. This is just for use in build log messages, where we already often print ‘’ or » etc. (Cf. jenkinsci/workflow-job-plugin#89.)
| } | ||
|
|
||
| /** | ||
| * Maximum number of seconds between upload/download attempts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think it would be good to use the same units or make the user pass a ChronoUnit/TimeUnit for waitMultiplier and waitMaximum (maybe also timeout) to avoid potential confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. I would like to see some tests for the general logic, but it seems like that would need a mocking framework which might get pretty nasty. I have no strong opinion about the package name.
Not necessarily a mocking framework, just a local server…but |
oleg-nenashev
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still do not like the current package name, but I am fine with it if @dwnusbaum is fine.
Subsumes #8.
@carlossg @kuisathaverat @oleg-nenashev @dwnusbaum